﻿using System;
using System.Collections.Generic;
using System.Text;

namespace SimpleSfxLib
{
    public class SFXUtility
    {
        /// <summary>
        /// Reads data from a stream until the end is reached. The
        /// data is returned as a byte array. An IOException is
        /// thrown if any of the underlying IO calls fail.
        /// </summary>
        /// <param name="stream">The stream to read data from</param>
        public static byte[] ReadFully(System.IO.Stream stream)
        {
            int initialLength = 32768;
            byte[] buffer = new byte[initialLength];
            int read = 0;

            int chunk;
            while (true)
            {
                chunk = stream.Read(buffer, read, buffer.Length - read);
                if (chunk <= 0)
                    break;

                read += chunk;

                // If we've reached the end of our buffer, check to see if there's
                // any more information
                if (read == buffer.Length)
                {
                    int nextByte = stream.ReadByte();

                    // End of stream? If so, we're done
                    if (nextByte == -1)
                    {
                        return buffer;
                    }

                    // Nope. Resize the buffer, put in the byte we've just
                    // read, and continue
                    byte[] newBuffer = new byte[buffer.Length * 2];
                    Array.Copy(buffer, newBuffer, buffer.Length);
                    newBuffer[read] = (byte)nextByte;
                    buffer = newBuffer;
                    read++;
                }
            }
            // Buffer is now too big. Shrink it.
            byte[] ret = new byte[read];
            Array.Copy(buffer, ret, read);
            return ret;
        }

        public static void BuildSFX(string zipFile, string exeFile, string outputFile)
        {
            System.IO.FileStream fs = new System.IO.FileStream(zipFile, System.IO.FileMode.Open, System.IO.FileAccess.Read);
            System.IO.FileStream fe = new System.IO.FileStream(exeFile, System.IO.FileMode.Open, System.IO.FileAccess.Read);
            System.IO.BinaryWriter bw = new System.IO.BinaryWriter(new System.IO.FileStream(outputFile, System.IO.FileMode.Create, System.IO.FileAccess.ReadWrite));
            //write all of 'fe'
            byte[] fb = ReadFully(fe);
            bw.Write(fb, 0, fb.Length);
            //the magic:
            bw.Write(new byte[] { (byte)'D', (byte)'A', (byte)'S', (byte)'3', (byte)'0', (byte)'S', (byte)'F', (byte)'X' }, 0, 8);
            bw.Write((int)fs.Length);
            fb = ReadFully(fs);
            bw.Write(Crc32.Compute(fb));
            bw.Write(fb, 0, fb.Length);
            bw.Close();
            fe.Close();
            fs.Close();
        }
    }
}
